#include "aceMesh_task.h"
#include "aceMesh_runtime_c.h"
#include "slave.h"


#define BLK 1024

void init_inner_core(double *data_A, double *data_B, long startii, long endii)
{
    long i,ii;
#ifdef MMEM
    for(ii=startii;ii<endii;++ii)
    {
        data_A[ii]=ii+1;
        data_B[ii]=1;
    }
#else
    double l_data_A[BLK];
    double l_data_B[BLK];
    //if(endii-startii-BLK>0) printf("%ld,%ld,%ld\n",endii,startii,endii-startii);
    
    for(i=startii; i<endii; i+=BLK)
    {
      //printf("start=%ld,%ld,%ld\n",startii,endii,i);
      for(ii=0;ii<BLK;ii++)
      {
        l_data_A[ii]=ii+i+1;
        l_data_B[ii]=1;
      }
      int bsize=BLK*8;
      int stride=0;
      int tsize=bsize;
      volatile int put_reply=0;
      athread_put(PE_MODE,&l_data_A[0]
                    ,&data_A[i]
                    ,tsize,(void*)&put_reply
                    ,stride,bsize);
      athread_put(PE_MODE,&l_data_B[0]
                    ,&data_B[i]
                    ,tsize,(void*)&put_reply
                    ,stride,bsize);
      while(put_reply!=2);
    }
#endif
}

void init_core(targs* args)
{
    init_inner_core(args->deta_A,args->deta_B,args->startii,args->endii);
}


void dot_inner_core(double *acc, double *A, double *B, long startii, long endii)
{
    long ii,i;
#ifdef MMEM
    for (ii = startii; ii < endii; ii++)
    {
        *acc += A[ii]*B[ii];
    }
    //printf("dot_product=%p,%lf\n",acc,*acc);
#else
    double l_data_A[BLK];
    double l_data_B[BLK];
    double local_acc=0.0;
    for(i=startii; i<endii; i+=BLK)
    {
      int bsize=BLK*8;
      int stride=0;
      int tsize=bsize;
      volatile int get_reply=0;
      athread_get(PE_MODE,&A[i]
                    ,&l_data_A[0]
                    ,tsize,(void*)&get_reply
                    ,0,stride,bsize);        
      athread_get(PE_MODE,&B[i]
                    ,&l_data_B[0]
                    ,tsize,(void*)&get_reply
                    ,0,stride,bsize);   
      while(get_reply!=2);
      //printf("start=%ld,%ld,%ld\n",startii,endii,i);
      for(ii=0;ii<BLK;ii++)
      {
          local_acc+=l_data_A[ii]*l_data_B[ii];
          
          //*acc+=l_data_A[ii]*l_data_B[ii];
          //*acc+=A[i+ii]*l_data_B[ii];
          //*acc+=A[i+ii]*B[i+ii];
      }
    }
    *acc+=local_acc;
    //printf("dot_product=%lf,%lf\n",local_acc,*acc);
 #endif
    //return *acc;
}
void dot_core(targs* args)
{
    dot_inner_core(args->acc, args->deta_A,args->deta_B,args->startii,args->endii);
}




#define mymin(a,b) ((a<b)?(a):(b))

void reduction_inner_core(double *result,double *acc, int length)
{
    long ii,i;
#ifdef MMEM
    //printf("length=%d\n",length);
    for ( ii = 0; ii < length; ii++)
    {
        //printf("reduction=%lf,%lf\n",acc[ii],*result);
       *result += acc[ii];
    }
#else
    double local_result=0;
    double local_acc[BLK]={0.0};
    for(i=0;i<length;i+=BLK)
    {
      int local_length=mymin(BLK,length-i);
      int bsize=local_length*8;
      volatile int get_reply=0;
      athread_get(PE_MODE,&acc[i]
                    ,&local_acc[0]
                    ,bsize,(void*)&get_reply
                    ,0,0,bsize);
      while(get_reply!=1);
      for(ii=0;ii<local_length;ii++)
      {
        local_result+=local_acc[ii];   
      }
    }
    *result=local_result;
#endif
}
void reduction_core(targs2* args)
{
    reduction_inner_core(args->result, args->acc, args->length);
}

